#include <qqtuserlistcontainer.h>
#include <QUuid>
#include <qqthostaddressmanager.h>
#include <QTimer>

#if 0 // defined(Q_OS_LINUX)
#include <sys/socket.h>
#endif

//#define p3line() QNoDebug()

enum MsgSecName
{
    CMD_TYPE = 0,
    CMD_CONTENT,
    CMD_MAX
};

QQtUserListContainer::QQtUserListContainer ( QObject* parent )
    : QObject ( parent )
{
    c0 = new QQtUdpClient ( this );
    p0 = new QQtUserListProtocol ( this );
    connect ( p0, SIGNAL ( signalRecvUserInformation ( const QQtDictionary& ) ),
              this, SLOT ( slotRecvUserInformation ( const QQtDictionary& ) ) );
    c0->installProtocol ( p0 );

    QQtHostAddressManager manager;
    QString ip = manager.getHostAddress();
    int port = 4410;
#if USE_HOST_ADDRESS
    c0->bind ( QHostAddress ( ip ), port, QQtUdpClient::DefaultForPlatform );
#else
    c0->bind ( port, QQtUdpClient::DefaultForPlatform );
#endif
    p3line() << c0->localAddress() << c0->localPort();

    c0->setServerAddress ( QHostAddress ( QHostAddress::Broadcast ), port );

#if 0 // defined(Q_OS_LINUX)
    int yes = 1;
    setsockopt ( c0->socketDescriptor(), SOL_SOCKET, SO_BROADCAST, &yes, sizeof ( yes ) );
#endif

    QUuid quuid = QUuid::createUuid();
    mUUid = quuid.toString().left ( 14 ).mid ( 1 );
    //qDebug() << mUUid;
    p0->setUUid ( mUUid );

    p0->setIPPort ( ip, port );

    mDictUser[mUUid]["ip"] = ip;
    mDictUser[mUUid]["port"] = port;
    mDictUser[mUUid]["uuid"] = mUUid;
    mDictUser[mUUid]["user_name"] = "Default";
    mDictUser[mUUid]["user_content"];
    mDictUser[mUUid]["heartbeats"] = 1;

    p0->setUserName ( "Default" );

    m_timer = new QTimer ( this );
    m_timer->setSingleShot ( false );
    m_timer->setInterval ( 5000 );
    connect ( m_timer, SIGNAL ( timeout() ), this, SLOT ( slotTimeout() ) );
    m_timer->start();

    //sendGetUserListRequest();
}

QQtUserListContainer::~QQtUserListContainer()
{
    m_timer->stop();
}

void QQtUserListContainer::setListeningAddress ( QHostAddress address, int port )
{
    c0->disconnectFromHost();

    c0->bind ( address, port, QQtUdpClient::DefaultForPlatform );
    p3line() << c0->localAddress() << c0->localPort();

    c0->setServerAddress ( QHostAddress ( QHostAddress::Broadcast ), port );

#if 0 // defined(Q_OS_LINUX)
    int yes = 1;
    setsockopt ( c0->socketDescriptor(), SOL_SOCKET, SO_BROADCAST, &yes, sizeof ( yes ) );
#endif

    QString ip = address.toString();
    p0->setIPPort ( ip, port );
    mDictUser[mUUid]["ip"] = ip;
    mDictUser[mUUid]["port"] = port;
}

void QQtUserListContainer::setListeningPort ( int port )
{
    c0->disconnectFromHost();
    QQtHostAddressManager manager;
    QString ip = manager.getHostAddress();
#if USE_HOST_ADDRESS
    c0->bind ( QHostAddress ( ip ), port, QQtUdpClient::DefaultForPlatform );
#else
    c0->bind ( port, QQtUdpClient::DefaultForPlatform );
#endif
    p3line() << c0->localAddress() << c0->localPort();

    c0->setServerAddress ( QHostAddress ( QHostAddress::Broadcast ), port );

#if 0 // defined(Q_OS_LINUX)
    int yes = 1;
    setsockopt ( c0->socketDescriptor(), SOL_SOCKET, SO_BROADCAST, &yes, sizeof ( yes ) );
#endif

    p0->setIPPort ( ip, port );
    mDictUser[mUUid]["ip"] = ip;
    mDictUser[mUUid]["port"] = port;
}

void QQtUserListContainer::setUserName ( QString username )
{
    p0->setUserName ( username );
    mDictUser[mUUid]["user_name"] = username;
}

void QQtUserListContainer::setUserContent ( QString key, QString value )
{
    p0->setUserContent ( key, value );
    mDictUser[mUUid]["user_content"][key] = value;
}

QString QQtUserListContainer::getUserName()
{
    return mDictUser[mUUid]["user_name"].getValue().toString();
}

QString QQtUserListContainer::getUserContent ( QString key )
{
    return mDictUser[mUUid]["user_content"][key].getValue().toString();
}

int QQtUserListContainer::timerInterval()
{
    return m_timer->interval();
}

void QQtUserListContainer::setTimerInterval ( int millsecond )
{
    m_timer->setInterval ( millsecond );
}

void QQtUserListContainer::sendGetUserListRequest()
{
    p0->sendWhoareyou();
}

void QQtUserListContainer::slotRecvUserInformation ( const QQtDictionary& data )
{
    QString uuid = data["uuid"].getValue().toString();
    mDictUser[uuid] = data;

    emit signalUserInfoChanged ( mDictUser );
    qDebug() << qPrintable ( mDictUser.toJson ( QJsonDocument::Indented ) );
}

void QQtUserListContainer::slotTimeout()
{
    //clear offline
    QStringList list1;
    QQtDictionaryMutableMapIterator itor ( mDictUser.getMap() );
    while ( itor.hasNext() )
    {
        itor.next();
        const QString& key = itor.key();
        QQtDictionary& d1 = itor.value();
        int hb0 = d1["heartbeats"].getValue().toInt();
        if ( hb0 != 0 )
        {
            //online
            d1["heartbeats"] = 0;
        }
        else
        {
            //offline
            list1.push_back ( key );
        }
    }

    QListIterator<QString> itor1 ( list1 );
    while ( itor1.hasNext() )
    {
        const QString& key = itor1.next();
        mDictUser.getMap().remove ( key );
        qDebug() << key << "offline";
    }

    //send to business level
    if ( !mDictUser.isEmpty() )
        emit signalUserInfoChanged ( mDictUser );

    sendGetUserListRequest();
}


QQtUserListProtocol::QQtUserListProtocol ( QObject* parent ) : QQtDataProtocol ( parent ) {}

QQtUserListProtocol::~QQtUserListProtocol() {}

void QQtUserListProtocol::setIPPort ( QString ip, int port )
{
    mIP = ip;
    mPort = port;
}

void QQtUserListProtocol::setUUid ( QString uuid )
{
    mUUid = uuid;
}

void QQtUserListProtocol::setUserName ( QString username )
{
    mUserName = username;
}

void QQtUserListProtocol::setUserContent ( QString key, QString value )
{
    mUserContent[key] = value;
}

void QQtUserListProtocol::sendWhoareyou()
{
    QQtDataSerialization data;
    data[CMD_TYPE] = "Who are you?";
    data.serialize();
    p3line() << data[CMD_TYPE].getValue().toString();
    sendMessage ( data );
}

void QQtUserListProtocol::recvWhoareyou()
{
    sendIam();
}

void QQtUserListProtocol::sendIam()
{
    QQtDataSerialization data;
    data[CMD_TYPE] = "I am";
    data[CMD_CONTENT]["ip"] = mIP;
    data[CMD_CONTENT]["port"] = mPort;
    data[CMD_CONTENT]["uuid"] = mUUid;
    data[CMD_CONTENT]["user_name"] = mUserName;
    data[CMD_CONTENT]["user_content"] = mUserContent;
    data[CMD_CONTENT]["heartbeats"] = 1;
    data.serialize();
    p3line() << data[CMD_TYPE].getValue().toString() << mIP << mPort;
    sendMessage ( data );

}

void QQtUserListProtocol::recvIam ( const QQtDictionary& data )
{
    emit signalRecvUserInformation ( data );
}

void QQtUserListProtocol::recvMessage ( const QQtDataSerialization& data )
{
    QQtDataSerialization ds0 = data;
    QString cmd_type = ds0[CMD_TYPE].getValue().toString();
    p3line() << cmd_type;
    if ( cmd_type == "Who are you?" )
    {
        recvWhoareyou();
    }
    else if ( cmd_type == "I am" )
    {
        QQtDictionary& data_section = ds0[CMD_CONTENT];
        recvIam ( data_section );
    }

}
